package com.test45_JUC;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * RecursiveAction分支任务，无返回值任务
 */
public class Demo29_RecursiveAction {

    public static void main(String[] args) throws Exception {
        CountSave save = new CountSave();   // 保存累加结果
        SumTask2 task = new SumTask2(1, 100, save);
        ForkJoinPool pool = new ForkJoinPool();  // 开启分支任务池
        pool.submit(task);  // 执行分支任务
        while (!task.isDone()) {    // 任务没有结束
            TimeUnit.MILLISECONDS.sleep(100);
        }
        if (task.isCompletedNormally()) {   // 任务执行完毕
            System.out.println("分支任务计算结果：" + save.getSum());
        }
    }
}

class CountSave {
    private Lock lock = new ReentrantLock();
    private int sum = 0;

    public void add(int num) {
        this.lock.lock();
        try {
            this.sum += num;
        } finally {
            this.lock.unlock();
        }
    }

    public int getSum() {
        return sum;
    }
}

/**
 * 实现数据累加的计算
 */
class SumTask2 extends RecursiveAction {
    private static final int THRESHOLD = 25;    // 分支阈值
    private int start;  // 开始计算数值
    private int end;    // 结束计算数值
    private CountSave save;  // 结果的存储

    public SumTask2(int start, int end, CountSave save) {
        this.start = start;
        this.end = end;
        this.save = save;
    }

    // 完成计算的处理
    @Override
    protected void compute() {
        // 所有的子分支的处理，以及所有相关分支的合并处理都在此方法之中完成
        int sum = 0;
        boolean isFork = (end - start) > THRESHOLD;    // 是否需要进行分支
        if (isFork) {   // 需要开启分支
            int middle = (start + end) / 2;
            SumTask2 leftTask = new SumTask2(this.start, middle, this.save);
            SumTask2 rightTask = new SumTask2(middle + 1, this.end, this.save);
            leftTask.fork();    // 开启左分支
            rightTask.fork();   // 开启右分支
        } else {    // 计算子分支
            for (int i = start; i <= end; i++) {
                sum += i;
            }
            this.save.add(sum);  // 保存累加结果
            System.out.printf("【%s】start = %d、end = %d、sum = %d%n",
                    Thread.currentThread().getName(), this.start, this.end, sum);
        }
    }
}
